package com.liuqi.loggers.core.config.xml;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

/**
 * 反射工具包
 *
 * @author liuqi
 * @date 2024/6/7 11:49
 **/
public class Reflect {

    /**
     * 反射为字段赋值
     *
     * @param instance  实例对象
     * @param filedName 字段名称
     * @param value     value
     */
    public static void setFiled(Object instance, String filedName, Object value) {
        filedName = toCamelCase(filedName);

        Field field = null;

        Class<?> instanceType = instance.getClass();

        do {
            try {
                field = instanceType.getDeclaredField(filedName);
                field.setAccessible(true);
                break;
            } catch (NoSuchFieldException e) {
                instanceType = instanceType.getSuperclass();
                if (instanceType == Object.class) {
                    throw new IllegalArgumentException(instance.getClass().getName() + " cannot find field [" + filedName + "]", e);
                }
            }
        } while (instanceType != null);


        Class<?> type = field.getType();
        try {
            if (type.isEnum()) {
                setEnum(instance, field, value);
            } else if (type.equals(List.class)) {
                addList(instance, field, value);
            } else if (type.equals(File.class)) {
                setFile(instance, field, value);
            } else {
                setObject(instance, field, value);
            }
        } catch (Throwable t) {
            throw new IllegalArgumentException(instance.getClass().getName() + " set value fail [" + filedName + "]", t);
        }
    }

    private static void setEnum(Object instance, Field field, Object value) throws Exception {
        Method valueOf = field.getType().getMethod("valueOf", String.class);
        Object invoke = valueOf.invoke(field.getType(), value);
        field.set(instance, invoke);
    }

    private static void setFile(Object instance, Field field, Object value) throws Exception {
        field.set(instance, new File(value.toString()));
    }

    private static void setObject(Object instance, Field field, Object value) throws Exception {
        Class<?> type = field.getType();
        if (type == int.class || type == Integer.class) {
            value = Integer.parseInt(value.toString());
        }
        if (type == boolean.class || type == Boolean.class) {
            value = Boolean.parseBoolean(value.toString());
        }
        field.set(instance, value);
    }

    private static void addList(Object instance, Field field, Object value) throws Exception {
        List list = (List) field.get(instance);
        list.add(value);
    }

    /**
     * 首字母大写
     *
     * @param val
     * @return
     */
    static String upperCase(String val) {
        char[] chars = val.toCharArray();
        if (chars[0] < 'a' || chars[0] > 'z') {
            return val;
        }
        chars[0] -= 32;
        return new String(chars);
    }

    /**
     * 横线转驼峰
     * <p>
     *     user-name -> userName
     * </p>
     *
     * @param underlineStr
     * @return
     */
    static String toCamelCase(String underlineStr) {
        if (underlineStr == null) {
            return null;
        }
        if (underlineStr.indexOf("-") == -1) {
            return underlineStr;
        }
        char[] charArray = underlineStr.toCharArray();
        boolean underlineBefore = false;
        StringBuffer buffer = new StringBuffer();
        for (int i = 0, l = charArray.length; i < l; i++) {
            if (charArray[i] == '-') {
                underlineBefore = true;
            } else if (underlineBefore) {
                if (charArray[i] > 'a' && charArray[i] < 'z') {
                    buffer.append(charArray[i] -= 32);
                } else {
                    buffer.append(charArray[i]);
                }
                underlineBefore = false;
            } else {
                buffer.append(charArray[i]);
            }
        }
        return buffer.toString();
    }

}
